package com.skt.service.impl;

import com.skt.service.BloomFilterService;
import com.skt.domain.VO.BloomFilterStatsVO;
import com.skt.domain.VO.BloomFilterHealthVO;
import com.skt.mapper.AuthMapper; // ✅ 修改：使用AuthMapper
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RBloomFilter;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.CommandLineRunner;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.List;
import java.util.concurrent.atomic.AtomicLong;

/**
 * 基于Redisson的布隆过滤器服务实现
 * 使用AuthMapper进行用户名查询，符合职责分离原则
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class BloomFilterServiceImpl implements BloomFilterService, CommandLineRunner {

    // ✅ 修改：使用AuthMapper替代UserMapper
    private final RedissonClient redissonClient;
    private final AuthMapper authMapper;

    private RBloomFilter<String> usernameBloomFilter;
    private AtomicLong insertionCount = new AtomicLong(0);

    @Value("${bloom.filter.username.name:username_bloom_filter}")
    private String bloomFilterName;

    @Value("${bloom.filter.username.expected-insertions:1000000}")
    private long expectedInsertions;

    @Value("${bloom.filter.username.false-probability:0.01}")
    private double falseProbability;

    /**
     * 初始化布隆过滤器
     */
    @Override
    public void initBloomFilter() {
        try {
            // 获取或创建布隆过滤器
            this.usernameBloomFilter = redissonClient.getBloomFilter(bloomFilterName);

            // 如果不存在则初始化
            if (!usernameBloomFilter.isExists()) {
                boolean initialized = usernameBloomFilter.tryInit(expectedInsertions, falseProbability);
                if (initialized) {
                    log.info("✅ 布隆过滤器初始化成功: name={}, expectedInsertions={}, falseProbability={}",
                            bloomFilterName, expectedInsertions, falseProbability);

                    // 预热数据：加载已存在的用户名
                    warmUpBloomFilter();
                } else {
                    log.error("❌ 布隆过滤器初始化失败");
                    throw new RuntimeException("布隆过滤器初始化失败");
                }
            } else {
                log.info("✅ 布隆过滤器已存在，跳过初始化");
                // 获取当前插入数量（近似值）
                insertionCount.set(usernameBloomFilter.count());
            }

        } catch (Exception e) {
            log.error("❌ 布隆过滤器初始化异常", e);
            throw new RuntimeException("布隆过滤器初始化异常", e);
        }
    }

    /**
     * 预热布隆过滤器：加载数据库中已存在的用户名
     */
    private void warmUpBloomFilter() {
        log.info("🔥 开始预热布隆过滤器...");
        long startTime = System.currentTimeMillis();
        long totalLoaded = 0;

        try {
            int batchSize = 1000;
            int page = 0;
            boolean hasMore = true;

            while (hasMore) {
                // ✅ 修改：使用AuthMapper查询用户名
                List<String> usernames = authMapper.selectUsernamesForBloomFilter(page * batchSize, batchSize);

                if (usernames.isEmpty()) {
                    hasMore = false;
                } else {
                    // 批量添加到布隆过滤器
                    for (String username : usernames) {
                        usernameBloomFilter.add(username);
                    }
                    totalLoaded += usernames.size();
                    insertionCount.addAndGet(usernames.size());
                    page++;

                    if (page % 10 == 0) {
                        log.debug("预热进度: 已加载 {} 个用户名", totalLoaded);
                    }

                    // 短暂休眠，避免对数据库造成压力
                    Thread.sleep(10);
                }
            }

            long costTime = System.currentTimeMillis() - startTime;
            log.info("✅ 布隆过滤器预热完成: 总数={}, 耗时={}ms", totalLoaded, costTime);

        } catch (Exception e) {
            log.error("❌ 布隆过滤器预热失败", e);
        }
    }

    /**
     * 检查用户名是否可能存在
     */
    @Override
    public boolean mightContain(String username) {
        if (usernameBloomFilter == null) {
            log.warn("布隆过滤器未初始化，降级到直接查询");
            return true; // 未初始化时保守返回true，走正常查询流程
        }

        boolean mightExist = usernameBloomFilter.contains(username);
        log.debug("布隆过滤器检查: username={}, result={}", username, mightExist);
        return mightExist;
    }

    /**
     * 添加用户名到布隆过滤器
     */
    @Override
    public void put(String username) {
        if (usernameBloomFilter != null) {
            usernameBloomFilter.add(username);
            insertionCount.incrementAndGet();
            log.debug("布隆过滤器添加用户名: {}", username);
        }
    }

    /**
     * 批量添加用户名
     */
    @Override
    public void putAll(java.util.Collection<String> usernames) {
        if (usernameBloomFilter != null) {
            for (String username : usernames) {
                usernameBloomFilter.add(username);
            }
            insertionCount.addAndGet(usernames.size());
            log.info("布隆过滤器批量添加: count={}", usernames.size());
        }
    }

    /**
     * 获取统计信息
     */
    @Override
    public BloomFilterStatsVO getStats() {
        if (usernameBloomFilter == null) {
            return new BloomFilterStatsVO(bloomFilterName, 0, 0, 0, 0, LocalDateTime.now(), false);
        }

        long count = insertionCount.get();
        return new BloomFilterStatsVO(
                bloomFilterName,
                expectedInsertions,
                count,
                falseProbability,
                calculateExpectedFalsePositiveRate(count),
                LocalDateTime.now(),
                isSaturated(count)
        );
    }

    /**
     * 检查健康状态
     */
    @Override
    public BloomFilterHealthVO checkHealth() {
        if (usernameBloomFilter == null) {
            return new BloomFilterHealthVO("ERROR", "布隆过滤器未初始化", 0, 0, true, System.currentTimeMillis());
        }

        long count = insertionCount.get();
        double currentRate = calculateExpectedFalsePositiveRate(count);
        boolean needsResize = count > expectedInsertions * 0.8;

        String status = needsResize ? "WARNING" : "HEALTHY";
        String message = needsResize ?
                "布隆过滤器接近饱和，建议扩容" : "布隆过滤器运行正常";

        return new BloomFilterHealthVO(status, message, count, currentRate, needsResize, System.currentTimeMillis());
    }

    /**
     * 计算预期误判率
     */
    private double calculateExpectedFalsePositiveRate(long elementCount) {
        if (elementCount == 0) return 0.0;
        return Math.pow(1 - Math.exp(-elementCount / (double) expectedInsertions), elementCount);
    }

    /**
     * 检查是否饱和
     */
    private boolean isSaturated(long elementCount) {
        return elementCount > expectedInsertions * 0.8;
    }

    /**
     * 应用启动后自动初始化
     */
    @Override
    public void run(String... args) throws Exception {
        log.info("🚀 启动布隆过滤器服务...");
        initBloomFilter();
    }

    /**
     * 定时监控布隆过滤器状态（每5分钟）
     */
    @Scheduled(fixedRate = 300000) // 5分钟
    public void monitorBloomFilter() {
        try {
            BloomFilterHealthVO health = checkHealth();
            if ("WARNING".equals(health.getStatus())) {
                log.warn("布隆过滤器监控告警: {}", health.getMessage());
            }
        } catch (Exception e) {
            log.error("布隆过滤器监控异常", e);
        }
    }
}